<?php
/**
 *
 * PHP versions 5
 *
 * Copyright (C)
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of ERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software
 * Fundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 *
 * @author Bastian Schröder <bs@chemanet.de>
 * @version 2007-03-12
 * @package rail
 */
class rail_factory{


	/**
	 * create new rail_container.
	 *
	 * @param rail_connector
	 * @param rail_object environment
	 * @param string OBJ_NAME
	 * @return rail_container
	 */
	public static function create_container ( $pRailConnector, $pEnvironment, $pName = "new_container" ) {
		$rail_id = rail_factory::make_object( $pRailConnector, $pEnvironment, "RAIL_CONTAINER", $pName);
		return rail_factory::get_object( $pRailConnector, $rail_id );
	}


	/**
	 * create new rail_document.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName
	 * @param string $pDocument
	 * @return rail_ducument
	 */
	public static function create_document ( $pRailConnector, $pEnvironment, $pName = "new_document", $pDocument = "" ) {
		$rail_id = rail_factory::make_object( $pRailConnector, $pEnvironment, "RAIL_DOCUMENT", $pName);
		$rail_object = rail_factory::get_object( $pRailConnector, $rail_id );

		if( strlen( trim($pDocument) ) > 0 )
			$rail_object->set_content( $pDocument );

		return $rail_object;
	}


	/**
	 * create new rail_group.
	 *
	 * @exception can't create new group without a name
	 * @exception group already exist
	 * @param rail_connector
	 * @param string OBJ_NAME
	 * @return rail_group
	 */
	public static function create_group ( $pRailConnector, $pName = "new group", $pEnvironment = "" ) {
		if( $pRailConnector->get_user()->get_name() != "root" )
			throw new rail_writepermission_exception( "Only root can do this!" );

		$environment = $pEnvironment instanceof rail_object?$pEnvironment:$pRailConnector->get_root()->get_group_container();

		if( !$environment->is_writeable( $pRailConnector->get_user() ) )
		 	throw new rail_writepermission_exception( $pEnvironment->get_path(), $pRailConnector->get_user() );
		if( count( $pRailConnector->get_root()->get_group_container()->inventory_search( "/".trim($pName)."/", array(OBJ_NAME)) ) > 0 )
			throw new rail_exception( "Can't create group: $pName already exist!", 0 );

		$pRailConnector->send_request( "INSERT INTO objects ( `type`, `environment`, `user`, `group`, `mode` ) VALUES ('RAIL_GROUP', '" . $environment->get_id() . "', '" . $pRailConnector->get_user()->get_id() . "', '" . $pRailConnector->get_user()->get_owner_group()->get_id() . "', '110100000')" );

		$data = $pRailConnector->send_request( "SELECT `id` FROM objects WHERE `type`='RAIL_GROUP' AND `environment`='" . $environment->get_id() . "' ORDER BY id DESC LIMIT 1" )->fetch_assoc();
		$new_rail_id = $data["id"];

		// add OBJ_NAME attribute
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_NAME','" . trim( $pName ) . "')" );

		$timestamp = time();
		// Set OBJ_TIME_CREATE and OBJ_TIME_LASTWRITE
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_TIME_CREATE','$timestamp')" );
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_TIME_LASTWRITE','$timestamp')" );
		// update OBJ_TIME_LASTWRITE from environment
		$pRailConnector->send_request( "UPDATE objects_attributes SET `value`='$timestamp' WHERE `object`='" . $environment->get_id() . "' AND `attribute`='OBJ_TIME_LASTWRITE'" );

		return rail_factory::get_object( $pRailConnector, $new_rail_id );
	}


	/**
	 * create new create_link.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName
	 * @param rail_object $pRailObject
	 * @return rail_link
	 */
	public static function create_link ( $pRailConnector, $pEnvironment, $pName = "new_link", $pRailObject = "" ) {
		// make a new rail link
		$rail_id = rail_factory::make_object( $pRailConnector, $pEnvironment, "RAIL_LINK", $pName);
		$rail_link = rail_factory::get_object( $pRailConnector, $rail_id );

		// set link if a target isset
		if( isset( $pRailObject ) && $pRailObject instanceof rail_object )
			$rail_link->set_link( $pRailObject );

		return $rail_link;
	}


	/**
	 * create new rail_object.
	 *
	 * @param rail_connector
	 * @param rail_object environment
	 * @param string OBJ_NAME
	 * @return rail_object
	 */
	public static function create_object ( $pRailConnector, $pEnvironment, $pName = "new_object" ) {
		$rail_id = rail_factory::make_object( $pRailConnector, $pEnvironment, "RAIL_OBJECT", $pName);
		return rail_factory::get_object( $pRailConnector, $rail_id );
	}


	/**
	 * create new rail_page.
	 *
	 * @param rail_connector $pRailConnector
	 * @param rail_object $pEnvironment
	 * @param string $pName
	 * @param string $pDocument
	 * @return rail_page
	 */
	public static function create_page ( $pRailConnector, $pEnvironment, $pName = "new_page" ) {
		$rail_id = rail_factory::make_object( $pRailConnector, $pEnvironment, "RAIL_PAGE", $pName);
		return rail_factory::get_object( $pRailConnector, $rail_id );
	}


	/**
	 * create new rail_user.
	 *
	 * @exception can't create new user without a name
	 * @exception can't create new user without a password
	 * @exception user already exist
	 * @param rail_connector
	 * @param string OBJ_NAME
	 * @param string RAIL_PASSWD
	 * @return rail_user
	 */
	public static function create_user ( $pRailConnector, $pName = "", $pPasswd = "", $pEnvironment = "" ) {
		if( $pRailConnector->get_user()->get_name() != "root" )
			throw new rail_writepermission_exception( "Only root can do this!" );

		$environment = $pEnvironment instanceof rail_object?$pEnvironment:$pRailConnector->get_root()->get_user_container();

		if( !$environment->is_writeable( $pRailConnector->get_user() ) )
		 	throw new rail_writepermission_exception( $environment, $pRailConnector->get_user() );
		if( strlen( trim( $pName) ) == 0 )
			throw new Exception( "Can't create new user without a name!", 0 );
		if( strlen( trim( $pPasswd) ) == 0 )
			throw new Exception( "Can't create new user without a password!", 0 );
		if( count( $pRailConnector->get_root()->get_user_container()->inventory_search( "/".trim($pName)."/", array(OBJ_NAME)) ) > 0 )
			throw new Exception( "Can't create user: $pName already exist!", 0 );

		$pRailConnector->send_request( "INSERT INTO objects ( `type`, `environment`, `group`, `mode` ) VALUES ('RAIL_USER', '" . $environment->get_id() . "', '" . rail_factory::get_object_by_path( $pRailConnector, "/" . $pRailConnector->get_root()->get_group_container()->get_name() . "/users/" )->get_id() . "', '110100000')" );

		$data = $pRailConnector->send_request( "SELECT `id` FROM objects WHERE `type`='RAIL_USER' AND `environment`='" . $environment->get_id() . "' ORDER BY id DESC LIMIT 1" )->fetch_assoc();
		$new_rail_id = $data["id"];

		$pRailConnector->send_request( "UPDATE objects SET `user`='$new_rail_id' WHERE id='$new_rail_id' LIMIT 1" );

		// add OBJ_NAME and RAIL_PASSWD attribute
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_NAME','" . trim( $pName ) . "')" );
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','RAIL_PASSWD','" . rtrim( md5( $pPasswd ) ) . "')" );

		$timestamp = time();
		// Set OBJ_TIME_CREATE and OBJ_TIME_LASTWRITE
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_TIME_CREATE','$timestamp')" );
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_TIME_LASTWRITE','$timestamp')" );
		// update OBJ_TIME_LASTWRITE from environment
		$pRailConnector->send_request( "UPDATE objects_attributes SET `value`='$timestamp' WHERE `object`='" . $environment->get_id() . "' AND `attribute`='OBJ_TIME_LASTWRITE'" );

		return rail_factory::get_object( $pRailConnector, $new_rail_id );
	}


	/**
	 * get object from databases. requires a valid rail_id.
	 *
	 * @exception object dosn't exist
	 * @exception type not supported
	 * @param rail_connector
	 * @param int unique rail id
	 * @return rail_object|rail_container|rail_root|rail_user|rail_group|rail_link
	 */
	public static function get_object ( $pRailConnector, $pId = 0 ) {
		// get type of possible rail object
		$rail_type = $pRailConnector->send_request( "SELECT `type` FROM objects WHERE `id`='$pId' LIMIT 1" )->fetch_assoc();
		$rail_type = $rail_type["type"];

		// throw an exception, if the rail object dosn't exist.
		if( $pId == 0 || strlen($rail_type) == 0 ){
				throw new rail_exception( "Object dosn't exist!", 0 );
				exit;
		}

		// return rail_object
		switch( $rail_type ){
			case "RAIL_OBJECT":
				return new rail_object( $pRailConnector, $pId );
				break;
			case "RAIL_CONTAINER":
				return new rail_container( $pRailConnector, $pId );
				break;
			case "RAIL_ROOT":
				return new rail_root( $pRailConnector, $pId );
				break;
			case "RAIL_USER":
				return new rail_user( $pRailConnector, $pId );
				break;
			case "RAIL_GROUP":
				return new rail_group( $pRailConnector, $pId );
				break;
			case "RAIL_DOCUMENT":
			case "RAIL_DOCUMENTS": //ugly hack
				return new rail_document( $pRailConnector, $pId );
				break;
			case "RAIL_PAGE":
				return new rail_page( $pRailConnector, $pId );
				break;
			case "RAIL_LINK":
				return new rail_link( $pRailConnector, $pId );
				break;
			// in case that type not supported
			default:
				throw new rail_exception( "Can't get object! type '$rail_type' not supported.", 0 );
		}
	}


	/**
	 * get object from databases. requires a valid path.
	 *
	 * @param rail_connector
	 * @param string path to rail_object
	 * @return rail_object|rail_container|rail_root|rail_user|rail_group|rail_link
	 */
	public static function get_object_by_path ( $pRailConnector, $pPath = "/" ) {
		$path = trim( $pPath );

		// remove last slash, if exist
		if( substr( $path, - 1 ) == "/" )
			$path = substr( $path, 0, strlen($path) - 1 );

		// explode path to array and remove first array object (root path)
		$path = explode( "/", $path );
		unset( $path[0] );

		// return if path is a path to root_room
		if( count($path) == 0 )
			return $pRailConnector->get_root();

		else{
			// for each path do
			$obj_id = $pRailConnector->get_root()->get_id();
			foreach( $path as $tracker ){
				$object_ids = array();

				$obj_name = substr($tracker, 0, strrpos( $tracker, "[" )?strrpos( $tracker, "[" ):strlen($tracker) );

				// search for tracker in current inventory
				$data = $pRailConnector->send_request(
					"SELECT objects.id
					 FROM objects,objects_attributes
					 WHERE objects.id = objects_attributes.object AND objects.environment ='$obj_id' AND objects_attributes.`attribute` = 'OBJ_NAME' AND objects_attributes.`value` = '" . urldecode( $obj_name ) . "' ORDER BY `id`"
				);

				// get enviroment id
				while( $data_row = $data->fetch_assoc() )
					$object_ids[] = $data_row["id"];


				if( strrpos( $tracker, "[" ) ){
					$obj_position = substr( $tracker, strrpos( $tracker, "[" ) + 1, strlen( $tracker ) - strrpos( $tracker, "[" ) - 2 );
					$obj_id = $object_ids[ $obj_position - 1 ];
				}
				else if( isset($object_ids[0]) )
					$obj_id = $object_ids[0];
				else
					throw new rail_exception( "Object dosn't exist!", 0 );
			}
			return rail_factory::get_object( $pRailConnector, $obj_id );

		}// End of else
	}


	/**
	 * Try to get a rail_object, requires a valid path. Return the rail_object or false otherwise.
	 *
	 * @param rail_connector
	 * @param string path to rail_object
	 * @return bool|rail_object|rail_container|rail_root|rail_user|rail_group|rail_link
	 */
	public static function is_rail_path ( $pRailConnector, $pPath = "/" ) {
		try{
			return rail_factory::get_object_by_path( $pRailConnector, $pPath );
		}
		catch( rail_exception $e ) {
			return false;
		}
	}


	/**
	 * this function can't call simple.
	 * create databases for a new object and set some basic objects.
	 * dosn't check wheather the given rail type is supportet or all neede attributes/relations are set.
	 * This is the reasis why this function has't call from outsite the PHPrail.
	 *
	 * @exception object dosn't exist
	 * @exception type not supported
	 * @param rail_connector
	 * @param rail_object environment
	 * @param string RAIL_TYPE
	 * @return int RAIL_ID
	 */
	public static function make_object ( $pRailConnector, $pEnvironment, $pRailType, $pName = "new" ) {
		$timestamp = time();

		if( !$pEnvironment instanceof rail_object )
			throw new rail_exception( "Can't create object: environment dosn't exist!", 0 );
		if( !$pEnvironment->is_writeable( $pRailConnector->get_user() ) )
		 	throw new rail_writepermission_exception( $pEnvironment->get_path(), $pRailConnector->get_user() );

		// Set object
		$pRailConnector->send_request( "INSERT INTO objects ( `type`, `environment`, `user`, `group`, `mode` ) VALUES ('" . strtoupper($pRailType) . "', '" . $pEnvironment->get_id() . "', '" . $pRailConnector->get_user()->get_id() . "', '" . $pRailConnector->get_user()->get_owner_group()->get_id() . "', '110100000')" );

		$data = $pRailConnector->send_request( "SELECT `id` FROM objects WHERE `type`='" . strtoupper($pRailType) . "' AND `environment`='" . $pEnvironment->get_id() . "' ORDER BY id DESC LIMIT 1" )->fetch_assoc();
		$new_rail_id = $data["id"];

		// Set OBJ_NAME
		$name = strlen( trim( $pName ) ) > 0?trim( $pName ):"new";
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_NAME','$name')" );

		// Set OBJ_TIME_CREATE and OBJ_TIME_LASTWRITE
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_TIME_CREATE','$timestamp')" );
		$pRailConnector->send_request( "INSERT INTO objects_attributes (`object`,`attribute`,`value`) VALUES ('$new_rail_id','OBJ_TIME_LASTWRITE','$timestamp')" );
		// update OBJ_TIME_LASTWRITE from environment
		$pRailConnector->send_request( "UPDATE objects_attributes SET `value`='$timestamp' WHERE `object`='" . $pEnvironment->get_id() . "' AND `attribute`='OBJ_TIME_LASTWRITE'" );

		return $new_rail_id;
	}

} // End of rail_factory
?>